/*
 * Niiuzu
 * Copyright (C) 2011  Thierry Nowak
 * 
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU General Public License along with
 * this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.niiuzu.server.dao.impl.util;

import com.googlecode.objectify.Key;
import com.googlecode.objectify.ObjectifyFactory;
import com.googlecode.objectify.ObjectifyService;
import com.niiuzu.server.dao.impl.dto.object.DtoObject;

/**
 * Gestionnaire des {@link com.googlecode.objectify.Key} utilisées pour les
 * relations entre les classes stockées dans le magasin de données.
 */
public class KeyUtil {

	private static final KeyUtil INSTANCE = new KeyUtil();

	/**
	 * Construit une nouvelle instance de {@link KeyUtil}.
	 */
	private KeyUtil() {

	}

	/**
	 * Récupère l'instance unique de {@link KeyUtil}.
	 */
	public static KeyUtil getInstance() {
		return INSTANCE;
	}

	/**
	 * Convertit une {@link Key} en {@link String} (valeur sérialisable et
	 * transcriptible côté client).
	 * 
	 * @param <T>
	 *            type de la classe {@link DtoObject} identifiée par
	 *            <tt>key</tt>.
	 * @param key
	 *            clef identifiant la classe stockée dans le magasin de données.
	 * @return identifiant sérialisable de la classe de type {@link String}.
	 * 
	 * @see com.googlecode.objectify.ObjectifyFactory#keyToString(Key)
	 */
	public <T extends DtoObject> String convertKeyToString(Key<T> key) {

		if (key == null) {
			return null;
		}

		ObjectifyFactory objectifyFactory = getObjectifyFactory();
		String encodedKey = objectifyFactory.keyToString(key);

		return encodedKey;
	}

	/**
	 * Convertit une {@link String} en {@link Key} qui puisse être stockée.
	 * 
	 * @param <T>
	 *            type de la classe {@link DtoObject} identifiée par
	 *            <tt>key</tt>.
	 * @param encodedKey
	 *            chaîne provenant de la conversion d'une {@link Key} (cf.
	 *            {@link #convertKeyToString(Key)}).
	 * @param dtoClass
	 *            classe du {@link DtoObject}
	 * @return clef correspondant à <tt>encodedKey</tt>.
	 * 
	 * @see com.googlecode.objectify.ObjectifyFactory#stringToKey(String)
	 */
	public <T extends DtoObject> Key<T> convertStringToKey(String encodedKey,
			Class<T> dtoClass) {

		if (encodedKey == null) {
			return null;
		}

		ObjectifyFactory objectifyFactory = getObjectifyFactory();
		Key<T> key = objectifyFactory.stringToKey(encodedKey);

		return key;
	}

	/**
	 * Récupère la clef d'un {@link DtoObject}.
	 * 
	 * @param <T>
	 *            type du {@link DtoObject}.
	 * @return {@link Key} correspondant à l'instance du {@link DtoObject}
	 *         stocké dans le magasin de données.
	 */
	public <T extends DtoObject> Key<T> getKeyFor(T dtoObject) {

		if (dtoObject == null) {
			return null;
		}

		ObjectifyFactory objectifyFactory = getObjectifyFactory();
		Key<T> key = objectifyFactory.getKey(dtoObject);

		return key;
	}

	/**
	 * Récupère une version sérialisable de la {@link Key} d'un
	 * {@link DtoObject}.
	 * 
	 * @param <T>
	 *            type du {@link DtoObject} stocké dans le magasin de données.
	 * @param dtoObject
	 *            instance de la classe stockée dans le magasin de données.
	 * @return {@link String} représentant la {@link Key} de <tt>dtoObject</tt>.
	 */
	public <T extends DtoObject> String getEncodedKeyFor(T dtoObject) {

		if (dtoObject == null) {
			return null;
		}

		ObjectifyFactory objectifyFactory = getObjectifyFactory();
		Key<T> key = objectifyFactory.getKey(dtoObject);
		String encodedKey = null;
		if (key != null) {
			encodedKey = objectifyFactory.keyToString(key);
		}

		return encodedKey;
	}

	/**
	 * Récupère une instance de {@link ObjectifyFactory}.
	 */
	private ObjectifyFactory getObjectifyFactory() {
		if (mockedObjectifyFactory != null) {
			return mockedObjectifyFactory;
		}
		return ObjectifyService.factory();
	}

	/* ********************************************************************** */
	/* ********************************************************************** */
	/* ********************************************************************** */

	private ObjectifyFactory mockedObjectifyFactory;

	/**
	 * JUnit - Définit un mock pour {@link ObjectifyFactory}.
	 */
	void setMockedObjectifyFactory(ObjectifyFactory mockedObjectifyFactory) {
		this.mockedObjectifyFactory = mockedObjectifyFactory;
	}
}
